package com.study.system.search.dao;

import com.alibaba.fastjson.JSON;
import com.study.system.entity.ElasticsearchEntity;
import com.study.system.entity.PageEntity;
import jakarta.annotation.Resource;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.CreateIndexResponse;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.reindex.DeleteByQueryRequest;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Repository;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Repository
public class ElasticsearchDAO {

    private static Logger logger = LoggerFactory.getLogger(ElasticsearchDAO.class);

    @Resource
    private RestHighLevelClient client;

    /**
     * 判断索引是否存在
     * @param indexName
     * @return
     */
    public boolean existsIndex(String indexName) throws IOException {
        //创建ES请求
        GetIndexRequest request = new GetIndexRequest(indexName);
        //判断索引是否存在
        boolean exists = client.indices().exists(request, RequestOptions.DEFAULT);
        logger.info("{}索引是否存在{}",indexName,exists);
        return exists;
    }

    /**
     * 创建索引
     * @param indexName
     */
    public void createIndex(String indexName) throws IOException {
        //创建索引的请求
        CreateIndexRequest request = new CreateIndexRequest(indexName);
        //执行创建索引
        CreateIndexResponse resp = client.indices().create(request, RequestOptions.DEFAULT);
        logger.info("{}索引创建完成{}",indexName,resp);
    }

    /**
     * 删除索引
     * @param indexName
     */
    public void deleteIndex(String indexName) throws IOException {
        //删除索引的请求
        DeleteIndexRequest request = new DeleteIndexRequest(indexName);
        //执行删除索引
        AcknowledgedResponse delete = client.indices().delete(request, RequestOptions.DEFAULT);
        logger.info("{}索引删除完成{}",indexName,delete);
    }

    /**
     * 批量插入
     * @param indexName
     * @param entities
     */
    public void insertBatch(String indexName, List<ElasticsearchEntity> entities) throws IOException {
        //创建批量请求
        BulkRequest request = new BulkRequest(indexName);
        //遍历实体类集合
        entities.forEach(entity -> {
            //添加数据的id和内容
            request.add(new IndexRequest()
                    .id(entity.getId().toString())
                    .source(JSON.toJSONString(entity.getData()), XContentType.JSON));
        });
        //执行批量请求
        client.bulk(request,RequestOptions.DEFAULT);
        logger.info("{}索引批量插入数据数量：{}",indexName,entities.size());
    }

    /**
     * 搜索
     * @param indexName 索引名称
     * @param current 当前页数
     * @param size 分页大小
     * @param search 搜索条件
     * @param sort 排序方式
     * @param clazz 数据类型
     * @return
     */
    public PageEntity search(String indexName, Long current, Long size,
                             Map<String,String> search,Map<String,String> sort,
                             Class clazz) throws IOException {
        //创建搜索请求
        SearchRequest request = new SearchRequest();
        //创建搜索生成器
        SearchSourceBuilder builder = new SearchSourceBuilder();
        //创建bool查询生成器
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        //遍历搜索条件，给bool查询添加搜索条件
        for(String key : search.keySet()){
            String value = search.get(key);
            if(StringUtils.hasText(value)){
                //设置过滤器添加短语查询 不分词
                boolQueryBuilder.filter(QueryBuilders.matchPhraseQuery(key,value));
            }
        }
        //设置布尔查询
        if(boolQueryBuilder.filter().size() > 0){
            builder.query(boolQueryBuilder);
        }
        //设置分页参数
        builder.from(current.intValue());
        builder.size(size.intValue());
        //设置排序参数
        if(StringUtils.hasText(sort.get("field")) && StringUtils.hasText(sort.get("type"))){
            String field = sort.get("field");
            String type = sort.get("type");
            builder.sort(new FieldSortBuilder(field).order(SortOrder.fromString(type)));
        }
        //执行搜索
        request.source(builder);
        SearchResponse resp = client.search(request, RequestOptions.DEFAULT);
        List data = new ArrayList();
        for(SearchHit hit : resp.getHits()){
            //将json转换为Java对象
            Object obj = JSON.parseObject(hit.getSourceAsString(),clazz);
            data.add(obj);
        }
        //包装搜索到的数据到分页实体类中
        PageEntity page = new PageEntity(current,size,resp.getHits().getTotalHits().value,data);
        return page;
    }

    public void saveOrUpdate(String indexName, ElasticsearchEntity entity) throws IOException {
        //创建索引操作请求
        IndexRequest request = new IndexRequest(indexName);
        //设置一个文档数据
        request.id(entity.getId().toString()).source(JSON.toJSONString(entity.getData()),XContentType.JSON);
        //通过rest客户端发送更新或添加请求
        client.index(request, RequestOptions.DEFAULT);
        logger.info("文档保存成功 {}",entity);
    }

    public void deleteById(String indexName, String id) throws IOException {
        //创建删除文档请求
        DeleteByQueryRequest request = new DeleteByQueryRequest(indexName);
        //设置删除条件
        request.setQuery(QueryBuilders.termQuery("id",id));
        client.deleteByQuery(request, RequestOptions.DEFAULT);
        logger.info("文档删除成功 {}", id);
    }
}
